#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <microhttpd.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>

#define PORT 8080
#define MJPEG_BOUNDARY "frame_boundary"

static AVFormatContext *format_context = NULL;
static AVCodecContext *codec_context = NULL;
static AVCodec *codec = NULL;
static AVFrame *frame = NULL;
static AVPacket packet;
static int video_stream_index = -1;
static struct MHD_Daemon *daemons = NULL;
struct MHD_Connection *con = NULL;
static int answer_to_connection(
    void *cls, struct MHD_Connection *connection,
    const char *url, const char *method,
    const char *version, const char *upload_data,
    size_t *upload_data_size, void **con_cls)
{
    printf("%s\n", __func__);
  con = connection;
    struct MHD_Response *response;
    int ret;
    const char *content_type = "multipart/x-mixed-replace; boundary=" MJPEG_BOUNDARY;
    

    // 这个地方直接返回 MJPEG 流，可以根据需要调整数据结构
    response = MHD_create_response_from_buffer(strlen("MJPEG stream"), (void *)"MJPEG stream", MHD_RESPMEM_PERSISTENT);
    // 设置响应内容类型为 MJPEG
    MHD_add_response_header(response, "Content-Type", content_type);

    // 设置 HTTP 响应并返回
    ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
    MHD_destroy_response(response);

    return MHD_NO;
}

int init_ffmpeg_streaming() {
    // 初始化 FFmpeg
    if (avformat_open_input(&format_context, "/dev/video0", NULL, NULL) != 0) {
        fprintf(stderr, "Could not open video device\n");
        return -1;
    }

    if (avformat_find_stream_info(format_context, NULL) < 0) {
        fprintf(stderr, "Could not find stream information\n");
        return -1;
    }

    // 查找视频流
    for (int i = 0; i < format_context->nb_streams; i++) {
        if (format_context->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
            video_stream_index = i;
            break;
        }
    }

    if (video_stream_index == -1) {
        fprintf(stderr, "No video stream found\n");
        return -1;
    }

    // 查找并打开解码器
    codec = avcodec_find_decoder(format_context->streams[video_stream_index]->codecpar->codec_id);
    if (!codec) {
        fprintf(stderr, "Codec not found\n");
        return -1;
    }

    codec_context = avcodec_alloc_context3(codec);
    if (avcodec_parameters_to_context(codec_context, format_context->streams[video_stream_index]->codecpar) < 0) {
        fprintf(stderr, "Could not copy codec parameters\n");
        return -1;
    }

    if (avcodec_open2(codec_context, codec, NULL) < 0) {
        fprintf(stderr, "Could not open codec\n");
        return -1;
    }

    // 分配帧
    frame = av_frame_alloc();
    if (!frame) {
        fprintf(stderr, "Could not allocate frame\n");
        return -1;
    }

    return 0;
}

int frame_to_mjpeg(AVFrame *frame, uint8_t **output_data, int *output_size) {
    AVPacket jpeg_packet;
    av_init_packet(&jpeg_packet);
    jpeg_packet.data = NULL;
    jpeg_packet.size = 0;
            AVCodec *jpeg_codec = avcodec_find_encoder(AV_CODEC_ID_MJPEG);
            AVCodecContext *jpeg_codec_ctx = avcodec_alloc_context3(jpeg_codec);

    // 检查帧格式，如果不是 YUV420P，则转换
    if (frame->format != AV_PIX_FMT_YUV420P) {
        AVFrame *converted_frame = av_frame_alloc();
        if (!converted_frame) {
            fprintf(stderr, "Could not allocate memory for converted frame\n");
            return -1;
        }

        converted_frame->format = AV_PIX_FMT_YUV420P;
        converted_frame->width = frame->width;
        converted_frame->height = frame->height;

        // 为转换后的帧分配内存
        if (av_image_alloc(converted_frame->data, converted_frame->linesize, frame->width, frame->height, AV_PIX_FMT_YUV420P, 1) < 0) {
            fprintf(stderr, "Could not allocate memory for converted frame data\n");
            av_frame_free(&converted_frame);
            return -1;
        }

        struct SwsContext *sws_ctx = sws_getContext(
            frame->width, frame->height, frame->format,
                                                    frame->width, frame->height, AV_PIX_FMT_YUV420P,
                                                    SWS_BICUBIC, NULL, NULL, NULL);
        sws_scale(sws_ctx, frame->data, frame->linesize, 0, frame->height, converted_frame->data, converted_frame->linesize);

            // 创建 JPEG 编码器
            jpeg_codec_ctx->strict_std_compliance = FF_COMPLIANCE_UNOFFICIAL;

            jpeg_codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
            jpeg_codec_ctx->width = converted_frame->width;
            jpeg_codec_ctx->height = converted_frame->height;
            jpeg_codec_ctx->time_base = (AVRational){1, 25};
            avcodec_open2(jpeg_codec_ctx, jpeg_codec, NULL);

            // 编码 RGB 帧为 JPEG
            AVPacket jpeg_packet;
            av_init_packet(&jpeg_packet);
            jpeg_packet.data = NULL;
            jpeg_packet.size = 0;
        // 发送转换后的帧进行编码
        //int ret = avcodec_send_frame(codec_context, converted_frame);
        int ret = avcodec_send_frame(jpeg_codec_ctx, converted_frame);
        if (ret < 0) {
            char errbuf[AV_ERROR_MAX_STRING_SIZE];
            av_strerror(ret, errbuf, sizeof(errbuf));
            fprintf(stderr, "1Error sending converted frame for JPEG encoding: %s\n", errbuf);
            av_frame_free(&converted_frame);
            sws_freeContext(sws_ctx);
            return -1;
        }

        av_frame_free(&converted_frame);
        sws_freeContext(sws_ctx);
    } else {
        // 如果帧已经是 YUV420P 格式，直接发送
        int ret = avcodec_send_frame(codec_context, frame);
        if (ret < 0) {
            char errbuf[AV_ERROR_MAX_STRING_SIZE];
            av_strerror(ret, errbuf, sizeof(errbuf));
            fprintf(stderr, "3Error sending frame for JPEG encoding: %s\n", errbuf);
            return -1;
        }
    }

    // 获取编码后的 JPEG 数据
    //int ret = avcodec_receive_packet(codec_context, &jpeg_packet);
    int ret = avcodec_receive_packet(jpeg_codec_ctx, &jpeg_packet);
    if (ret < 0) {
        char errbuf[AV_ERROR_MAX_STRING_SIZE];
        av_strerror(ret, errbuf, sizeof(errbuf));
        fprintf(stderr, "Error receiving JPEG packet: %s\n", errbuf);
        return -1;
    }

    // 赋值给输出参数
    *output_data = jpeg_packet.data;
    *output_size = jpeg_packet.size;

    return 0;
}

// 处理 MJPEG 流的函数
void handle_mjpeg_stream(struct MHD_Connection *connection)
{
    uint8_t *jpeg_data = NULL;
    int jpeg_size = 0;

    printf("%s\n", __func__);
    while (av_read_frame(format_context, &packet) >= 0) {
        if (packet.stream_index == video_stream_index) {
            if (avcodec_send_packet(codec_context, &packet) == 0) {
                while (avcodec_receive_frame(codec_context, frame) == 0) {
                    // 将视频帧转换为 MJPEG
                    if (frame_to_mjpeg(frame, &jpeg_data, &jpeg_size) == 0) {
                        // 构建 MJPEG 响应头
                        char header[1024];
                        snprintf(header, sizeof(header),
                                 "--" MJPEG_BOUNDARY "\r\n"
                                 "Content-Type: image/jpeg\r\n"
                                 "Content-Length: %d\r\n\r\n", jpeg_size);

                        // 发送 MJPEG 响应头
                        MHD_queue_response(connection, MHD_HTTP_OK, header);

                        // 发送 JPEG 数据
                        MHD_queue_response(connection, MHD_HTTP_OK, (char *)jpeg_data);
                    }
                }
            }
            av_packet_unref(&packet);
        }
    }
}

int main() {
    // 初始化 FFmpeg 视频流捕获
  avdevice_register_all();
  avformat_network_init();
    if (init_ffmpeg_streaming() != 0) {
        fprintf(stderr, "Error initializing FFmpeg streaming\n");
        return 1;
    }

    // 启动 HTTP 服务器
    daemons = MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION, PORT, NULL, NULL, &answer_to_connection, NULL, MHD_OPTION_END);
    if (daemons == NULL) {
        fprintf(stderr, "Error starting HTTP server\n");
        return 1;
    }

    printf("Server running on port %d...\n", PORT);
    
    // 在后台处理 MJPEG 流
    handle_mjpeg_stream(con);

    // 等待客户端连接
    getchar();

    // 停止服务器
    MHD_stop_daemon(daemons);

    return 0;
}

